using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Orbifold.Trefoil
{

    /// <summary>
    /// Color picker control that pops up on clicking some other control.
    /// </summary>
    public class PopupColorPicker : Control
    {
        public event EventHandler<ColorEventArgs> PopupClosed;
        #region Fields
        Popup colorPanelPopup;
        private Button chooseButton, moreButton, dropButton;


        Rectangle currentColorRectangle;
        ListBox list;
        /// <summary>
        /// the list of predefined colors for data binding to the popup
        /// </summary>
        private static List<Brush> mColors = new List<Brush>();
        /// <summary>
        /// Set here the colors you like the most.
        /// </summary>
        private static Brush[] predefinedBrushes = new Brush[]{
                Brushes.Black, Brushes.Brown, Brushes.OliveDrab, Brushes.DarkGreen, 
                Brushes.DarkTurquoise, Brushes.DarkBlue, Brushes.Indigo, Brushes.DimGray, 
            
                Brushes.DarkRed, Brushes.Orange, Brushes.Gold, Brushes.Green,
                Brushes.Teal, Brushes.Blue, Brushes.SteelBlue, Brushes.Silver,

                Brushes.Red, Brushes.Orange, Brushes.Lime, Brushes.SeaGreen, 
                Brushes.Aqua, Brushes.LightBlue, Brushes.Violet, Brushes.Gray,

                Brushes.Pink, Brushes.Gold, Brushes.Yellow, Brushes.Green, 
                Brushes.Turquoise, Brushes.SkyBlue, Brushes.Plum, Brushes.Gray,

                Brushes.Pink, Brushes.Tan, Brushes.LightYellow, Brushes.LightGreen, 
                Brushes.Turquoise, Brushes.LightBlue, Brushes.Lavender, Brushes.White,
            };
        #endregion

        #region Properties

        /// <summary>
        /// the SelectedColor field
        /// </summary>
        private Color mSelectedColor;
        /// <summary>
        /// Gets or sets the SelectedColor
        /// </summary>
        public Color SelectedColor
        {
            get { return mSelectedColor; }
            set { mSelectedColor = value; }
        }

        public Button ChooseButton
        {
            get { return chooseButton; }
            set { chooseButton = value; }
        }
        /// <summary>
        /// Gets the colors.
        /// </summary>
        /// <value>The colors.</value>
        public static List<Brush> Colors
        {
            get { return PopupColorPicker.mColors; }

        }

        /// <summary>
        /// Gets or sets a value indicating whetherto show the initial/parent button.
        /// </summary>
        /// <value><c>true</c> if showing the button; otherwise, <c>false</c>.</value>
        public bool ShowParentButton
        {
            get { return (bool)GetValue(ShowParentButtonProperty); }
            set { SetValue(ShowParentButtonProperty, value); }

        }

        // Using a DependencyProperty as the backing store for ShowParentButton.  This enables animation, styling, binding, etc...
        public static DependencyProperty ShowParentButtonProperty =
            DependencyProperty.Register("ShowParentButton", typeof(bool), typeof(PopupColorPicker));


        public string PlacementTarget
        {
            get { return (string)GetValue(PlacementTargetProperty); }
            set { SetValue(PlacementTargetProperty, value); }

        }

        // Using a DependencyProperty as the backing store for ShowParentButton.  This enables animation, styling, binding, etc...
        public static DependencyProperty PlacementTargetProperty =
            DependencyProperty.Register("PlacementTarget", typeof(string), typeof(PopupColorPicker));


        /// <summary>
        /// the PlacementTargetControl field
        /// </summary>
        private UIElement mPlacementTargetControl;
        /// <summary>
        /// Gets or sets the PlacementTargetControl
        /// </summary>
        public UIElement PlacementTargetControl
        {
            get { return mPlacementTargetControl; }
            set { mPlacementTargetControl = value;
            if (colorPanelPopup != null)
                colorPanelPopup.PlacementTarget = value;
            }
        }




        #endregion

        #region Commands

        /// <summary>
        /// the ChooseCommand field
        /// </summary>
        //private static RoutedCommand mColorselectedCommand = new RoutedCommand();
        /// <summary>
        /// Gets or sets the ChooseCommand
        /// </summary>
        //public static RoutedCommand ColorSelectedCommand
        //{
        //    get { return mColorselectedCommand; }
        //    set { mColorselectedCommand = value; }
        //}
        /// <summary>
        /// the ChooseCommand field
        /// </summary>
        private static RoutedCommand mChooseCommand = new RoutedCommand();
        /// <summary>
        /// Gets or sets the ChooseCommand
        /// </summary>
        public static RoutedCommand ChooseCommand
        {
            get { return mChooseCommand; }
            set { mChooseCommand = value; }
        }
        /// <summary>
        /// the MoreCommand field
        /// </summary>
        private static RoutedCommand mMoreCommand = new RoutedCommand();
        /// <summary>
        /// Gets or sets the MoreCommand
        /// </summary>
        public static RoutedCommand MoreCommand
        {
            get { return mMoreCommand; }
            set { mMoreCommand = value; }
        }
        #endregion

        #region Constructor

        /// <summary>
        /// Initializes the <see cref="PopupColorPicker"/> class.
        /// </summary>
        static PopupColorPicker()
        {
            //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
            //This style is defined in themes\generic.xaml
            DefaultStyleKeyProperty.OverrideMetadata(typeof(PopupColorPicker), new FrameworkPropertyMetadata(typeof(PopupColorPicker)));
            for (int i = 0; i < predefinedBrushes.Length; i++)
            {
                mColors.Add(predefinedBrushes[i]);
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="PopupColorPicker"/> class.
        /// </summary>
        public PopupColorPicker()
            : base()
        {
            //when a ColorButton in the palet is clicked the ColorChosenEvent will bubble to the control and will be handled
            //as specified in this line.
            this.AddHandler(ColorButton.ColorChosenEvent, new RoutedEventHandler(this.ColorChosenHandler));
        }
        #endregion

        #region Methods

        /// <summary>
        /// Handler for the click event of a little ColorButton.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="args">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ColorChosenHandler(object source, RoutedEventArgs args)
        {
            SolidColorBrush brush = (args.OriginalSource as ColorButton).Background as SolidColorBrush;
            currentColorRectangle.Fill = brush;
            mSelectedColor = brush.Color;
            ClosePopup();
            RaiseOnPopupClosed();
        }
        /// <summary>
        /// When overridden in a derived class, is invoked whenever application code or internal processes call <see cref="M:System.Windows.FrameworkElement.ApplyTemplate"></see>.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            colorPanelPopup = this.GetTemplateChild("PART_Popup") as Popup;
            chooseButton = this.GetTemplateChild("PART_ChooseButton") as Button;
            moreButton = this.GetTemplateChild("PART_MoreButton") as Button;
            currentColorRectangle = this.GetTemplateChild("PART_CurrentColor") as Rectangle;

            //dropButton = this.GetTemplateChild("PART_DropButton") as Button;
            list = this.GetTemplateChild("PART_List") as ListBox;
            if (chooseButton != null)
            {
                chooseButton.CommandBindings.Add(new CommandBinding(ChooseCommand, new ExecutedRoutedEventHandler(OnChooseClick)));
                if (ShowParentButton)
                {
                    chooseButton.Visibility = Visibility.Visible;
                }
                else
                    chooseButton.Visibility = Visibility.Collapsed;
            }
            if (moreButton != null)
                moreButton.CommandBindings.Add(new CommandBinding(MoreCommand, new ExecutedRoutedEventHandler(OnMoreClick)));
            if (colorPanelPopup != null)
            {
                if (PlacementTarget != null)
                {
                    UIElement target = LogicalTreeHelper.FindLogicalNode(LogicalTreeRoot, PlacementTarget) as UIElement;
                    if (target != null)
                    {
                        colorPanelPopup.PlacementTarget = target;
                        PlacementTargetControl = target;
                    }
                }
            }
            if (list != null)
            {
                list.CommandBindings.Add(new CommandBinding(MoreCommand, new ExecutedRoutedEventHandler(OnMoreClick)));
                //for (int i = 0; i < list.Items.Count; i++)
                {
                    Button btn = list.ItemTemplate.LoadContent() as Button;
                    //list.ItemTempl
                    //btn.CommandBindings.Add(new CommandBinding(MoreCommand, new ExecutedRoutedEventHandler(OnMoreClick)));
                    btn.Click += new RoutedEventHandler(ColorButton_Click);
                }
            }

        }

        /// <summary>
        /// Handles the Click event of the ColorButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        void ColorButton_Click(object sender, RoutedEventArgs e)
        {
            this.RaiseEvent(new RoutedEventArgs(ColorButton.ColorChosenEvent, this));
        }

        /// <summary>
        /// Called when PART_ChooseButton is clicked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        public void OnChooseClick(object sender, RoutedEventArgs args)
        {
            //myPopup.CustomPopupPlacementCallback =
            //    new CustomPopupPlacementCallback(placePopup);
            if (colorPanelPopup != null)
                colorPanelPopup.IsOpen = true;

        }
        /// <summary>
        /// Called when 'More...' button is clicked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        public void OnMoreClick(object sender, RoutedEventArgs args)
        {
            ClosePopup();
            ColorPickerDialog dialog = new ColorPickerDialog();
            dialog.StartingColor = System.Windows.Media.Colors.ForestGreen;
            bool? dialogResult = dialog.ShowDialog();
            if (dialogResult != null && (bool)dialogResult == true)
            {


                mSelectedColor = dialog.SelectedColor;
                currentColorRectangle.Fill = new SolidColorBrush(mSelectedColor);
                RaiseOnPopupClosed();

            }
            colorPanelPopup.IsOpen = false;
        }


        /// <summary>
        /// Closes the popup.
        /// </summary>
        public void ClosePopup()
        {
            if (colorPanelPopup != null)
            {
                colorPanelPopup.IsOpen = false;
               
            }
        }
        private void RaiseOnPopupClosed()
        {
            if (PopupClosed != null)
                PopupClosed(this, new ColorEventArgs(mSelectedColor));
        }

        /// <summary>
        /// Shows the popup.
        /// </summary>
        public void ShowPopup()
        {
            if (colorPanelPopup != null)
                colorPanelPopup.IsOpen = true;
        }
        /// <summary>
        /// Gets the root of the logical tree.
        /// </summary>
        /// <value>The logical tree root.</value>
        private UIElement LogicalTreeRoot
        {
            get
            {
                UIElement elem = this;

                while (LogicalTreeHelper.GetParent(elem) != null)
                {
                    elem = LogicalTreeHelper.GetParent(elem) as UIElement;
                }
                return elem;
            }
        }
        #endregion
    }


    /// <summary>
    /// The little color button in the color palet
    /// </summary>
    public class ColorButton : Button
    {
        public static readonly RoutedEvent ColorChosenEvent = EventManager.RegisterRoutedEvent("ColorChosen", RoutingStrategy .Bubble, typeof( RoutedEventHandler), typeof(ColorButton));

        /// <summary>
        /// Add/remove handler of the event
        /// </summary>
        public event RoutedEventHandler ColorChosen
        {
            add { AddHandler(ColorChosenEvent, value); }
            remove { RemoveHandler(ColorChosenEvent, value); }
        }

        /// <summary>
        /// Raises the color chosen event.
        /// </summary>
        void RaiseColorChosenEvent()
        {
            RoutedEventArgs newEventArgs = new RoutedEventArgs(ColorButton.ColorChosenEvent);
            RaiseEvent(newEventArgs);
        }

        /// <summary>
        /// Called when the button is clicked.
        /// </summary>
        protected override void OnClick()
        {
            RaiseColorChosenEvent();
        }

    }

    public class ColorEventArgs : EventArgs
    {


        /// <summary>
        /// the Color field
        /// </summary>
        private Color mColor;
        /// <summary>
        /// Gets or sets the Color
        /// </summary>
        public Color Color
        {
            get { return mColor; }
            set { mColor = value; }
        }

        public ColorEventArgs(Color color)
        {
            mColor = color;
        }
    }
}
